﻿//
// *************************************************************************************
// WP-Framework
// 
// Developed by
// Lukas Kretschmar (lkretschmar.dev@bluewin.ch)
//
// Switzerland, Copyright (c) 2013 lkretschmar
// This content is released under the MIT License (http://opensource.org/licenses/MIT).
//     
// *************************************************************************************
//
//


using Microsoft.VisualStudio.TestTools.UnitTesting;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects;
using System;
using System.Linq;
using KretschIT.WP_Fx.Testing;
using System.Reflection;
using System.Collections.Generic;
using KretschIT.WP_Fx.EasyMoq.Generator.Items;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Events;
using KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Inheritance;

namespace KretschIT.WP_Fx.EasyMoq.Generator.Tests
{
    [TestClass]
    public class EasyMoqClassTemplateHelperTest
    {
        private IEasyMoqClassTemplateHelper classHelper;

        [TestInitialize]
        public void Init()
        {
            this.classHelper = new EasyMoqClassTemplateHelper(new NamingFactory(new List<Type>()));
        }

        [TestMethod]
        public void Test_Ctor_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
            {
                new EasyMoqClassTemplateHelper(null);
            });
        }

        [TestMethod]
        public void Test_GetReturnType_ReferenceType()
        {
            var type = classHelper.GetReturnType(typeof(string));
            Assert.AreEqual("System.String", type);
        }

        [TestMethod]
        public void Test_GetReturnType_ValueType()
        {
            var type = classHelper.GetReturnType(typeof(int));
            Assert.AreEqual("System.Int32", type);
        }

        [TestMethod]
        public void Test_GetReturnyTyp_Void()
        {
            var type = classHelper.GetReturnType(typeof(void));
            Assert.AreEqual("void", type);
        }

        [TestMethod]
        public void Test_GetReturnType_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    classHelper.GetReturnType(null);
                });
        }

        [TestMethod]
        public void Test_GetReturnType_OfGeneric()
        {
            var type = classHelper.GetReturnType(typeof (IEnumerable<int>));
            Assert.AreEqual("System.Collections.Generic.IEnumerable<System.Int32>", type);
        }

        [TestMethod]
        public void Test_GetReturnType_OfGenericDefition()
        {
            var type = classHelper.GetReturnType(typeof (IEnumerable<>));
            Assert.AreEqual("System.Collections.Generic.IEnumerable<T>", type);
        }

        [TestMethod]
        public void Test_HasReturnType_Type()
        {
            Assert.IsTrue(classHelper.HasReturnType(typeof(string)));
        }

        [TestMethod]
        public void Test_HasReturnType_Void()
        {
            Assert.IsFalse(classHelper.HasReturnType(typeof(void)));
        }

        [TestMethod]
        public void Test_HasReturnType_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    classHelper.HasReturnType(null);
                });
        }

        [TestMethod]
        public void Test_CreateParameters_WithoutTypes()
        {
            var type = typeof(ITestObject);
            var method = type.GetMethod("Action", new Type[] { typeof(string), typeof(string) });

            var parameters = classHelper.CreateArguments(method.GetParameters(), false);

            Assert.AreEqual("first, second", parameters);
        }

        [TestMethod]
        public void Test_CreateParameters_NoArguments()
        {
            var type = typeof(ITestObject);
            var method = type.GetMethod("Action", new Type[0]);

            var parameters = classHelper.CreateArguments(method.GetParameters(), false);

            Assert.AreEqual(string.Empty, parameters);
        }

        [TestMethod]
        public void Test_CreateParameters_WithTypes()
        {
            var type = typeof(ITestObject);
            var method = type.GetMethod("Action", new Type[] { typeof(string), typeof(string) });

            var parameters = classHelper.CreateArguments(method.GetParameters(), true);

            Assert.AreEqual("System.String first, System.String second", parameters);
        }

        [TestMethod]
        public void Test_CreateParameters_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    classHelper.CreateArguments(null, false);
                });
        }

        [TestMethod]
        public void Test_CreateGenericArguments()
        {
            var type = typeof(ITestGenericMethod);
            var method = type.GetMethod("GenericArgument");

            var generic = this.classHelper.CreateGenericArgumentsFor(method);

            Assert.AreEqual("<T>", generic);
        }

        [TestMethod]
        public void Test_CreateMultiGenericArguments()
        {
            var type = typeof(ITestGenericMethod);
            var method = type.GetMethod("MultiGenericArgument");

            var generic = this.classHelper.CreateGenericArgumentsFor(method);

            Assert.AreEqual("<T1, T2>", generic);
        }

        [TestMethod]
        public void Test_CreateNonGenericArguments()
        {
            var type = typeof(ITestGenericMethod);
            var method = type.GetMethod("NonGeneric");

            var generic = this.classHelper.CreateGenericArgumentsFor(method);

            Assert.AreEqual(string.Empty, generic);
        }

        [TestMethod]
        public void Test_CreateGenericArgumentsFor_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    this.classHelper.CreateGenericArgumentsFor((MethodInfo)null);
                });
        }

        [TestMethod]
        public void Test_CreateParameters_Generic()
        {
            var type = typeof(ITestGenericMethod);
            var method = type.GetMethod("MultiGenericArgument");

            var arguments = this.classHelper.CreateArguments(method.GetParameters(), true);

            Assert.AreEqual("T1 arg1, T2 arg2", arguments);
        }

        [TestMethod]
        public void Test_CreateParameters_Mixed()
        {
            var type = typeof(ITestGenericMethod);
            var method = type.GetMethod("MixedArguments");

            var arguments = this.classHelper.CreateArguments(method.GetParameters(), true);

            Assert.AreEqual("System.Int32 i, T1 arg1, System.String s", arguments);
        }

        [TestMethod]
        public void Test_GetGenericConstraint_Method()
        {
            var type = typeof(ITestGenericMethod);
            var method = type.GetMethod("GenericConstraintAction");

            var constraint = this.classHelper.GetGenericConstraintOf(method.GetGenericArguments());

            Assert.AreEqual(" where T : class, new()", constraint);
        }

        [TestMethod]
        public void Test_CreateGenericClassArguments()
        {
            var type = typeof(ITestSimpleGenericObject<int>);

            var generic = this.classHelper.CreateGenericArgumentsFor(type);

            Assert.AreEqual("<T>", generic);
        }

        [TestMethod]
        public void Test_CreateGenericClassArguments_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    this.classHelper.CreateGenericArgumentsFor((Type)null);
                });
        }

        [TestMethod]
        public void Test_CreateGenericClassArguments_MultiArguments()
        {
            var type = typeof(ITestComplexGenericObject<int, string, char>);

            var generic = this.classHelper.CreateGenericArgumentsFor(type);

            Assert.AreEqual("<T1, T2, T3>", generic);
        }

        [TestMethod]
        public void Test_CreateGenericClassArguments_NonGenericClass()
        {
            var type = typeof(ITestObject);

            var generic = this.classHelper.CreateGenericArgumentsFor(type);

            Assert.AreEqual(string.Empty, generic);
        }

        [TestMethod]
        public void Test_CreateGenericArgumentsWith()
        {
            var types = new List<Type> { typeof(string), typeof(int) };

            var generic = this.classHelper.CreateGenericArgumentsWith(types);

            Assert.AreEqual("<System.String, System.Int32>", generic);
        }

        [TestMethod]
        public void Test_CreateGenericArgumentsWith_NullArgument()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    this.classHelper.CreateGenericArgumentsWith(null);
                });
        }

        [TestMethod]
        public void Test_CreateGenericArgumentsFor_Event_None()
        {
            var type = typeof(ITestAllEvent);
            var e = type.GetEvent("SimpleEvent");

            var arguments = this.classHelper.CreateGenericArgumentsFor(e);

            Assert.AreEqual("", arguments);
        }

        [TestMethod]
        public void Test_CreateGenericArgumentsFor_Event_Null()
        {
            ExceptionAssert.Throws<ArgumentNullException>(() =>
                {
                    this.classHelper.CreateGenericArgumentsFor((EventInfo)null);
                });
        }

        [TestMethod]
        public void Test_CreateGenericArgumensFor_Event()
        {
            var type = typeof(ITestAllEvent);
            var e = type.GetEvent("GenericEvent");

            var arguments = this.classHelper.CreateGenericArgumentsFor(e);

            Assert.AreEqual("<System.EventArgs>", arguments);
        }

        [TestMethod]
        public void Test_UniqueTypeName()
        {
            var helper = new EasyMoqClassTemplateHelper(new NamingFactory(new List<Type> { typeof(ITestSimpleGenericObject<>) }));
            var name = helper.GetUniqueNameOf(typeof(ITestSimpleGenericObject<>));
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestSimpleGenericObject", name);
        }

        [TestMethod]
        public void Test_UniqueTypeName_WithNamespaces()
        {
            var helper = new EasyMoqClassTemplateHelper(new NamingFactory(new List<Type> { typeof(ITestSimpleGenericObject<>), typeof(Helpers.OtherObjects.ITestSimpleGenericObject<>) }));
            var firstName = helper.GetUniqueNameOf(typeof(ITestSimpleGenericObject<>));
            var secondName = helper.GetUniqueNameOf(typeof(Helpers.OtherObjects.ITestSimpleGenericObject<>));
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.Objects.ITestSimpleGenericObject", firstName);
            Assert.AreEqual("KretschIT.WP_Fx.EasyMoq.Generator.Tests.Helpers.OtherObjects.ITestSimpleGenericObject", secondName);
        }

        [TestMethod]
        public void Test_GetEventsOfType()
        {
            var type = typeof(ITop);
            var events = this.classHelper.GetEventsOf(type);
            Assert.AreEqual(2, events.Count());
        }

        [TestMethod]
        public void Test_GetEventsOfType_Overrloaded()
        {
            var type = typeof(ITopOverload);
            var events = this.classHelper.GetEventsOf(type);
            Assert.AreEqual(1, events.Count());
        }

        [TestMethod]
        public void Test_GetMethodsOfType()
        {
            var type = typeof(ITop);
            var methods = this.classHelper.GetMethodsOf(type);
            Assert.AreEqual(2, methods.Count());
        }

        [TestMethod]
        public void Test_GetMethodsOfType_Overloaded()
        {
            var type = typeof(ITopOverload);
            var methods = this.classHelper.GetMethodsOf(type);
            Assert.AreEqual(1, methods.Count());
        }

        [TestMethod]
        public void Test_GetPropertiesOfType()
        {
            var type = typeof(ITop);
            var properties = this.classHelper.GetPropertiesOf(type);
            Assert.AreEqual(2, properties.Count());
        }

        [TestMethod]
        public void Test_GetPropertiesOfType_Overloaded()
        {
            var type = typeof(ITopOverload);
            var properties = this.classHelper.GetPropertiesOf(type);
            Assert.AreEqual(1, properties.Count());
            var p = properties.Single();
            Assert.IsTrue(p.CanRead);
            Assert.IsTrue(p.CanWrite);
        }

        [TestMethod]
        public void Test_GetMethodOfEvent()
        {
            var type = typeof(ITestAllEvent);
            var m = this.classHelper.GetSignatureOf(type.GetEvent("SimpleEvent"));
            Assert.IsNotNull(m);
        }

        [TestMethod]
        public void Test_GetRaiseMethodOfEvent()
        {
            var type = typeof(ITestAllEvent);
            var methodName = this.classHelper.GetRaiseMethodOf(type.GetEvent("SimpleEvent"));
            Assert.AreEqual("RaiseSimpleEventEvent", methodName);
        }
    }
}
